[rust] honor --browser-version in Selenium Manager Electron driver resolution#17567
[rust] honor --browser-version in Selenium Manager Electron driver resolution#17567gaurav0107 wants to merge 4 commits into
Conversation
…solution Fixes SeleniumHQ#17549. ElectronManager::request_driver_version() always read the redirect from electron/electron/releases/latest, discarding any user-supplied --browser-version. Because Electron release tags equal the chromedriver version that ships with that release, when the user pins a concrete browser version we can use it directly and skip the network roundtrip. Stable / unstable / empty browser versions retain the existing /releases/latest fallback. Also gate the metadata cache write on a non-empty major_browser_version, mirroring the chrome.rs guard, so empty-keyed driver entries no longer get persisted.
Assert the resolved driver path actually contains the requested browser version. Without this, the test only verified that selenium manager exits successfully, which the buggy code path also did (it just downloaded the wrong version). Using --output json + the existing get_driver_path helper makes the regression assertion explicit.
Review Summary by QodoHonor --browser-version in Selenium Manager Electron driver resolution
WalkthroughsDescription• Honor user-supplied --browser-version in Electron driver resolution • Use concrete browser version directly instead of always fetching /releases/latest • Gate metadata cache writes on non-empty major_browser_version to prevent empty-keyed entries • Add regression test asserting resolved driver path contains requested version Diagramflowchart LR
A["User supplies --browser-version"] --> B{Is concrete version?}
B -->|Yes| C["Use version directly as driver version"]
B -->|No| D["Fetch /releases/latest redirect"]
C --> E["Resolve driver path"]
D --> E
E --> F["Cache metadata if version non-empty"]
File Changes1. rust/src/electron.rs
|
Code Review by Qodo
1.
|
| Ok(driver_version) | ||
| } | ||
| _ => { | ||
| self.assert_online_or_err(OFFLINE_REQUEST_ERR_MSG)?; | ||
|
|
||
| let latest_url = format!( | ||
| "{}{}", | ||
| self.get_driver_mirror_url_or_default(DRIVER_URL), | ||
| LATEST_RELEASE | ||
| ); | ||
| let driver_version = | ||
| read_redirect_from_link(self.get_http_client(), latest_url, self.get_logger())?; | ||
| // Electron releases are tagged by Electron version, and the | ||
| // chromedriver asset shipped in each release matches that tag. | ||
| // When the user pins a concrete browser version (e.g. | ||
| // `--browser-version 36.2.1`), that version is the driver | ||
| // version we want; resolving via `/releases/latest` would | ||
| // discard the user's request and return the latest tag instead. | ||
| let browser_version = self.get_browser_version().to_string(); | ||
| let driver_version = if !browser_version.is_empty() | ||
| && !self.is_browser_version_stable() | ||
| && !self.is_browser_version_unstable() | ||
| { | ||
| browser_version | ||
| } else { |
There was a problem hiding this comment.
3. Cache overrides pinned patch 🐞 Bug ≡ Correctness
request_driver_version still checks metadata by major_browser_version before applying the pinned --browser-version logic, so a cached entry for major "36" can override a user request for "36.2.1" and return a different patch driver version. This can silently violate the user’s explicit version pin.
Agent Prompt
### Issue description
Even after this PR, `ElectronManager::request_driver_version()` may return a cached driver version based on `major_browser_version` before it considers the user’s pinned full `--browser-version`. Because the metadata key is only the major component, different patch pins under the same major can conflict.
### Issue Context
- Metadata lookup for driver version keys on `major_browser_version`.
- `get_major_browser_version()` returns only the major component for non-channel inputs.
- The new pinned-version behavior lives only in the metadata-miss branch.
### Fix Focus Areas
- rust/src/electron.rs[103-155]
- rust/src/metadata.rs[123-139]
- rust/src/lib.rs[1365-1374]
### What to change
One of the following (prefer the one consistent with project behavior):
- If `--browser-version` is a specific pinned version, bypass metadata lookup entirely and return the requested (normalized) version.
- Or, key metadata lookups/writes for Electron on the full pinned version (not just the major) when `is_browser_version_specific()` is true, so separate patch pins don’t collide.
Also consider adding a regression test that runs two different `--browser-version 36.x.y` values back-to-back and asserts the second run resolves to the second requested patch.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
|
@gaurav0107: Two notes:
|
…rmalize leading v - Move the pinned-version short-circuit ahead of the metadata cache lookup so a cached entry keyed on `major_browser_version` can no longer override an explicit patch pin (e.g. cached `36` overriding `36.2.1`). - Only treat the pin as an exact Electron release tag when it is a *specific* version (contains a dot). Major-only inputs like `36` keep using the `/releases/latest` fallback - Electron has no `v36` tag and emitting one would build a 404 download URL. Regression test added. - Strip a single leading `v` / `V` so inputs like `v36.2.1` no longer collide with the `v` prefix added by `get_driver_url()`. We deliberately do not call `parse_version()` here because it would mangle prerelease suffixes such as `36.0.0-beta.1` that Electron release tags carry. - Add unit tests for `normalize_pinned_version` covering specific versions, leading-v normalization, prerelease preservation, major-only fallback, channel names, and empty/whitespace input. Refs PR SeleniumHQ#17567 review by titusfortner; addresses the three Qodo flags.
|
Code review by qodo was updated up to the latest commit 1f74218 |
|
@titusfortner thanks for the review. All three Qodo flags are addressed in 1f74218:
Note on the failing CI checks: |
Description
ElectronManager::request_driver_version()always read the GitHub redirect fromelectron/electron/releases/latestand used the resolved tag as the driver version. The user-supplied--browser-versionwas only consulted as a metadata cache key (viaget_major_browser_version()); it never affected the actual URL resolution. As a result,get_driver_url()formatted the chromedriver download URL using whatever version came back from/releases/latestrather than the version the user requested.For Electron, the chromedriver shipped inside each release is tagged identically to the Electron release itself (
https://github.com/electron/electron/releases/download/v{VERSION}/chromedriver-v{VERSION}-{platform}.zip), so when the caller already supplies a concrete version, we can use it directly and avoid the network roundtrip altogether.The fix:
_ =>arm ofrequest_driver_version, ifget_browser_version()is a concrete version (non-empty, notstable, not an unstable channel likedev/beta/nightly), return it directly as the driver version./releases/latestredirect path unchanged.major_browser_version(mirrors the existing guard inchrome.rs:338), so we no longer persist empty-keyed driver entries.A regression test (
electron_browser_version_test) was added inrust/tests/electron_tests.rsthat pins--browser-version 36.2.1and asserts the manager succeeds. Locally:The pre-existing
electron_latest_test(which exercises the unchanged latest-fallback path) also still passes.Motivation and Context
Closes #17549.
When Selenium Manager is asked to provision the Electron driver against a specific Electron version, the user expects the chromedriver from that release. Today, every request - regardless of
--browser-version- silently downloads whatever is at/releases/latest, so cross-version testing of Electron apps via SM is effectively broken.Types of changes
Checklist
electron_browser_version_testadded, exercises the new specific-version path;electron_latest_testcontinues to cover the unchanged latest-fallback path.cargo build,cargo fmt --check,cargo test --lib, and bothelectron_*integration tests pass.AI assistance disclosure
Per the CONTRIBUTING.md AI Tool Use section: AI assistance was used to draft the patch and the regression test. I read, reviewed, and ran the changes locally, and I am the responsible author. No
Co-Authored-Bytrailer for AI tooling per project policy.